package com.gitee.qdbp.filling.biz;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.gitee.qdbp.able.beans.KeyString;
import com.gitee.qdbp.able.beans.KeyValue;
import com.gitee.qdbp.filling.api.EntityDataTypedFillService;
import com.gitee.qdbp.tools.utils.ConvertTools;
import com.gitee.qdbp.tools.utils.NamingTools;
import com.gitee.qdbp.tools.utils.StringTools;
import com.gitee.qdbp.tools.utils.VerifyTools;

/**
 * 实体数据填充单一类型处理基础实现类
 *
 * @author zhaohuihua
 * @version 20210113
 */
public abstract class BaseEntityDataFillFieldValueBasic implements EntityDataTypedFillService {

    protected boolean skipDataFill(Map<String, Object> data) {
        return false;
    }

    protected boolean skipSourceValue(Serializable sourceValue) {
        return false;
    }

    // originalData: key=sourceValue
    // valueMaps: key=sourceValue, value=targetValue
    protected void fillValueToOriginalData(Map<? extends Serializable, List<DataFillor>> originalData, Map<?, ?> valueMaps) {
        // # 将targetValue填充至originalData
        for (Map.Entry<? extends Serializable, List<DataFillor>> entry : originalData.entrySet()) {
            Serializable sourceValue = entry.getKey();
            if (valueMaps.containsKey(sourceValue)) {
                Object targetValue = valueMaps.get(sourceValue);
                List<DataFillor> fillors = entry.getValue();
                for (DataFillor fillor : fillors) {
                    fillor.fillValues(targetValue);
                }
            }
        }
    }

    /**
     * options多个字段以逗号分隔, 默认的填充字段为源字段去掉Id/Code后缀, 加上Name<br>
     * -- createUser,updateUser<br>
     * -- 等于createUser-createUserName,updateUser-updateUserName<br>
     * 也可以自定义转换关系<br>
     * -- creatorId-createUser,updatorId-updateUser<br>
     * @param options 转换规则
     * @return 解析后的规则, key=fieldName, value=targetName
     */
    protected List<KeyString> parseOptions(String options) {
        List<KeyString> list = new ArrayList<>();
        if (options == null || options.trim().length() == 0) {
            return list;
        }
        String[] array = StringTools.split(options, ',');
        for (String option : array) {
            option = option.trim();
            int index = option.indexOf('-');
            if (index < 0) {
                list.add(new KeyString(option, convertToTargetName(option)));
            } else if (index > 0) {
                String source = option.substring(0, index).trim();
                String target = option.substring(index + 1).trim();
                list.add(new KeyString(source, target));
            // } else {
                // 横框开头? 忽略!
            }
        }
        return list;
    }

    protected Map<? extends Serializable, List<DataFillor>> collectFillInfos(Iterable<Map<String, Object>> list,
            List<KeyString> options) {
        Map<Serializable, List<DataFillor>> sourceMaps = new HashMap<>();
        for (Map<String, Object> map : list) {
            if (skipDataFill(map)) {
                continue;
            }
            DataFillor fillor = collectDataFillor(map, options);
            if (fillor.getFillFields().isEmpty()) {
                continue;
            }
            // key=targetName, value=sourceValue
            for (KeyValue<? extends Serializable> item : fillor.getFillFields()) {
                if (sourceMaps.containsKey(item.getValue())) {
                    sourceMaps.get(item.getValue()).add(fillor);
                } else {
                    List<DataFillor> fillors = ConvertTools.toList(fillor);
                    sourceMaps.put(item.getValue(), fillors);
                }
            }
        }
        return sourceMaps;
    }

    protected DataFillor collectDataFillor(Map<String, Object> data, List<KeyString> options) {
        DataFillor fillor = new DataFillor(data);
        for (KeyString item : options) {
            String sourceName = item.getKey();
            String targetName = item.getValue();
            // # 先按入参指定的字段名, 判断是否存在字段值
            Object sourceValue = data.get(sourceName);
            if (VerifyTools.isNotBlank(sourceValue) && data.get(targetName) == null) {
                if (sourceValue instanceof Serializable) {
                    Serializable value = (Serializable) sourceValue;
                    if (!skipSourceValue(value)) {
                        fillor.addFillField(targetName, value);
                    }
                }
                continue;
            }
            // # 如果不存在, 转换为驼峰命名或下划线命名再次判断
            String convertedSourceName;
            String convertedTargetName;
            if (isCamelNaming(sourceName)) {
                // 入参是驼峰命名, 转换为下划线命名
                convertedSourceName = NamingTools.toUnderlineString(sourceName).toUpperCase();
                convertedTargetName = NamingTools.toUnderlineString(targetName).toUpperCase();
            } else {
                // 入参是下划线命名, 转换为驼峰命名
                convertedSourceName = NamingTools.toCamelString(sourceName);
                convertedTargetName = NamingTools.toCamelString(targetName);
            }
            Object convertedSourceValue = data.get(convertedSourceName);
            if (VerifyTools.isNotBlank(convertedSourceValue) && data.get(convertedTargetName) == null) {
                if (convertedSourceValue instanceof Serializable) {
                    Serializable value = (Serializable) convertedSourceValue;
                    if (!skipSourceValue(value)) {
                        fillor.addFillField(convertedTargetName, value);
                    }
                }
                continue;
            }
        }
        return fillor;
    }

    protected String convertToTargetName(String source) {
        if (isCamelNaming(source)) {
            String target = source;
            if (target.endsWith("Id")) {
                target = StringTools.removeSuffix(target, "Id");
            } else if (target.endsWith("Code")) {
                target = StringTools.removeSuffix(target, "Code");
            }
            return target + "Name";
        } else {
            String target = source;
            if (target.endsWith("_ID")) {
                target = StringTools.removeSuffix(target, "_ID");
            } else if (target.endsWith("_CODE")) {
                target = StringTools.removeSuffix(target, "_CODE");
            }
            return target + "_NAME";
        }
    }

    protected boolean isCamelNaming(String source) {
        char[] chars = source.toCharArray();
        for (int i = 0, z = chars.length; i < z; i++) {
            char c = source.charAt(i);
            if (c >= 'a' && c <= 'z') {
                return true; // 存在小写字母, 即判定为驼峰命名
            }
        }
        return false;
    }

    protected static class DataFillor {

        // key=targetName, value=sourceValue
        private final List<KeyValue<? extends Serializable>> fillFields;
        private final Map<String, Object> originalData;

        public DataFillor(Map<String, Object> originalData) {
            this.originalData = originalData;
            this.fillFields = new ArrayList<>();
        }

        protected void addFillField(String targetName, Serializable sourceValue) {
            this.fillFields.add(new KeyValue<>(targetName, sourceValue));
        }

        public List<KeyValue<? extends Serializable>> getFillFields() {
            return this.fillFields;
        }

        public void fillValues(Object targetValue) {
            for (KeyValue<?> item : fillFields) {
                this.originalData.put(item.getKey(), targetValue);
            }
        }
    }
}
